<?php

require("user.inc.php");
require("template.inc.php");

tpl_header();
?>
<h2>The .gitgraph command</h2>

<p>Here's a grammar of the language in ABNF syntax (don't get too hung up on
the parsing ambiguities, please, I'm sure you'll understand what I mean).

<p><strong>Don't like grammars?</strong> Don't worry, I have examples below
you can crib from, including explanations.

<p>Like grammars? Never seen ABNF before? Don't worry, it's easy to understand
if you know the basic ideas behind grammars. Most things are self-explanatory,
just the weird number/asterisk prefixes might need some explaining. Basically
<code>a*b</code> is the same as a <code>{a,b}</code> suffix in most of today's
regular expression dialects (both <code>a</code> and <code>b</code> are
optional, as always), and an <code>a</code> prefix is the same as a
<code>{a}</code> suffix in regex.

<pre><code class="abnf">
UALPHA = %x41-5A
IDENT = ALPHA / DIGIT / "-" / "/" / "."
SPACE = 1*WSP
literal-string = DQUOTE *(%x00-21 / %x23-FF) DQUOTE ; strings can contain anything except double quotes; no escaping mechanism
dimmed = "?"
derived = "'"
commit-id = 1*(IDENT) [derived] [dimmed]
ref-id = 1*IDENT
auto-commit-id = (UALPHA / DIGIT) *IDENT [derived] [dimmed]
kw-align = ("align" / "a") SPACE
kw-branch = ("branch" / "b") SPACE
kw-commit = ("commit" / "c") SPACE
kw-dashed = ("dashed" / "-")
kw-dim = ("dim" / "d")
kw-dotted = ("dotted" / ".")
kw-edge = ("edge" / "e") SPACE
kw-label = ("label" / "l") SPACE
kw-merge = ("merge" / "m") SPACE
kw-mergeto = ("mergeto" / "m") SPACE
kw-remote = ("remote" / "r") SPACE
kw-symref = ("symref" / "s") SPACE
kw-tag = ("tag" / "t") SPACE
kw-up = ("up" / "u") SPACE

graph = ".gitgraph" SPACE definition *(*WSP ";" *WSP definition) *WSP
definition = cluster-def / align-def / commit-def / edge-def / merge-def / symref-def / up-def

cluster-def = ""

align-def = kw-align commit-id 1*(SPACE commit-id)

commit-def = (kw-commit commit / commit-short) *(SPACE commit)
commit = commit-id *WSP [commit-attrs]
commit-short = auto-commit-id *WSP [commit-attrs]
commit-attrs = "[" *WSP commit-attr *(SPACE commit-attr) *WSP "]"
commit-attr = cattr-branch / cattr-label / cattr-mergeto / cattr-remote / cattr-tag
cattr-branch = kw-branch ref-id
cattr-label = kw-label (1*IDENT / literal-string)
cattr-mergeto = kw-mergeto commit-id
cattr-remote = kw-remote ref-id
cattr-tag = kw-tag ref-id

edge-def = kw-edge commit-id commit-id edge-attrs
edge-attrs = edge-attr *(SPACE edge-attr)
edge-attr = eattr-dashed / eattr-dim / eattr-dotted / eattr-label
eattr-dashed = kw-dashed
eattr-dim = kw-dim
eattr-dotted = kw-dotted
eattr-label = kw-label (1*IDENT / literal-string)

merge-def = kw-merge commit-id 2*(SPACE commit-id)

symref-def = kw-symref ref-id / "HEAD" [dimmed]

up-def = kw-up commit-id 1*(SPACE commit-id)
</code></pre>

<h3>Examples</h3>

<p>We'll be working our way up here. (Line breaks inserted for clarity, of
course on IRC you can't use any.)

<table class="large">
<tr><th>Code</th><th>Generated graph</th></tr>
<tr><td><pre class="wrap">
.gitgraph A B C
</pre></td><td><img src="/g/NT.png"></td></tr>
<tr><td><pre class="wrap">
.gitgraph A B C;
D E F[mergeto C]
</pre>
<p>My first merge, yay!
</td><td><img src="/g/NU.png"></td></tr>
<tr><td><pre class="wrap">
.gitgraph A B C;;
D E F[mergeto C]
</pre>
<p>More spacing because the empty definition starts a cluster.
</td><td><img src="/g/NV.png"></td></tr>
<tr><td><pre class="wrap">
.gitgraph A B C;;
D E F[mergeto C];
align A D
</pre>
<p>Maybe we want to align the two root commits at the same level...
</td><td><img src="/g/OC.png"></td></tr>
<tr><td><pre class="wrap">
.gitgraph A B C[branch master?];;
A' B' C'[branch master]
</pre>
<p>Three new features at once!
<ul>
<li>We add branch labels to some commits.
<li>The question mark <em>dims</em> a commit or pretty much anything,
  typically to show an old version/state.
<li><code>A</code> and <code>A'</code> are automatically linked to visualize
  commit rewriting, e.g. rebases.
</ul>
<p>The cluster split (<code>;;</code>) helps the layouting &ndash; in this
case it helped Graphviz render the two histories in the correct order.
However, this is a little hit-and-miss.
</td><td><img src="/g/OD.png"></td></tr>
<tr><td><pre class="wrap">
.gitgraph A B C[tag v0.1 remote origin/master]
</pre>
<p>We can do some other types of references, too.
</td><td><img src="/g/NY.png"></td></tr>
<tr><td><pre class="wrap">
.gitgraph A B C[branch master remote origin/master];
  HEAD? master;
  symref FETCH_HEAD origin/master;;
A D E[branch test];
  HEAD test
</pre>
<p>New lessons:
<ul>
<li>We can draw a dimmed HEAD and a proper one; easy!
<li>HEAD is a special case of a symbolic ref; the "symref" keyword is needed
  if you want to draw symbolic refs with other names.
<li>Two series of commits can share commits. The first usage determines
  where it is rendered. Generally you can reuse commit names virtually
  everywhere.
<li>It really pays off putting any related refs in the same cluster.
  Experiment with putting the <code>;;</code> in any different place and
  you'll see what I mean.
</ul></td><td><img src="/g/N-.png"></td></tr>
<tr><td><pre class="wrap">
.gitgraph A[label "I like really long commit titles"] B C;
A D E
</pre>
<p>If you want to make a commit description super verbose, you can put it as a
label and still reuse the commit's original name in other parts of the
definition.
</td><td><img src="/g/O0.png"></td></tr>
<tr><td><pre class="wrap">
.gitgraph A B;
  merge C B ... X[label ...];
  edge C X label "this history is boring" dashed;;
F; G; edge G F
</pre>
<p>Thought I didn't have you covered with exotic features like octopus merges?
Hah, think again.
<p>Also, notice how I can just "make up" commits as children for the merge and
they will be auto-created. Whenever you mention a commit somewhere that isn't
part of a sequence, it will be created as an (otherwise) unlinked commit,
until you do something else that links it up.

<p>You noticed the elliptical commits, I'm sure. Basically you can use "..."
once to automatically create a differently-rendered fake commit that suggests
that there are more commits than the graph shows. If you want to use it a
second time, well, two commits can't have the same name, hence the label trick
which achieves the same look.

<p>Finally, you can use the "edge" command to add a label to an existing edge.
It will not automatically create a new edge, though, as can be seen in the
right part of the example. (We can also style edges using the keywords
"dashed", "dim" and "dotted".)
</td><td><img src="/g/Pc.png"></td></tr>
<tr><th colspan="2">Troubleshooting example</th></tr>
<tr><td><p>Attempt 1:
<pre class="wrap">
.gitgraph A B C[branch origin/master?] D? E? F?[branch master?];
C G H I[branch origin/master];
I D' E' F'[branch master]
</pre>
<p>This looks a little chaotic, doesn't it? How can we fix that? Well, ideally
D-F and D'-F' would be aligned on the same level, right? Let's try that
next...
</td><td><img src="/g/OL.png"></td></tr>
<tr><td><p>Attempt 2:
<pre class="wrap">
.gitgraph A B C[branch origin/master?] D? E? F?[branch master?];
C G H I[branch origin/master];
I D' E' F'[branch master];
<strong>align D? D'</strong>
</pre>
<p>Wow, that's even worse! (Spoiler: if we repeat the same for E and F, it
doesn't get much better...)

<p>Fortunately there's a different approach if we take a step back. We told
Graphviz that D should be above C (due to the arrow between them) and D'
should be above I. Can't we tell it that D should be above I, too? Yes we can!
Let's check it out:
</td><td><img src="/g/OM.png"></td></tr>
<tr><td><p>Attempt 3:
<pre class="wrap">
.gitgraph A B C[branch origin/master?] D? E? F?[branch master?];
C G H I[branch origin/master];
I D' E' F'[branch master];
<strong>up I D?</strong>
</pre>
<p>Say, that looks quite decent. Let's stick with this one.
</td><td><img src="/g/OR.png"></td></tr>
</table>

<p>Some more remarks without examples:

<ul>
<li>Commits and all ref types share the same namespace. You can't have a
commit and a branch that are both called <code>master</code>, for example.
<li>You can use the <code>edge</code> keyword to link arbitrary nodes if you
really want to, but please don't. I'm not sure my sanity will survive that.
</ul>

<script src="hljs/highlight.pack.js"></script>
<script>hljs.highlightAll();</script>
<?php tpl_footer();

